#include "header.h"
#include "EventLoop.hpp"
#include "Acceptor.hpp"
#include "TcpConnection.hpp"

#include <sys/epoll.h>

namespace wd
{

EventLoop::EventLoop(Acceptor & acceptor)
: _epfd(createEpollFd())
, _isLooping(false)
, _acceptor(acceptor)
, _evtArr(1000)
{
    addEpollReadEvent(_acceptor.fd());
}

EventLoop::~EventLoop()
{
    close(_epfd);
}

void EventLoop::loop()
{
    _isLooping = true;

    while(_isLooping)
    {
        waitEpollFd();
    }
}

// 要与 loop 函数运行在不同的线程
void EventLoop::unloop()
{
    _isLooping = false;
}

void EventLoop::waitEpollFd()
{
    // epoll_wait
    int nready = epoll_wait(_epfd , _evtArr.data() , _evtArr.size() , 5000);

    if(nready == -1 && errno == EINTR)
    {
        return ;
    }
    else if(nready == -1)
    {
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }
    else if(nready == 0)
    {
        printf("epoll 连接超时\n");
    }
    // nread > 0
    else
    {
        for(int i = 0 ; i < nready ; ++i)
        {
            int fd = _evtArr[i].data.fd;

            if(fd == _acceptor.fd())
            {
                handleNewConnection();
            }
            else
            {
                handleMessage(fd);
            }
        }
    }
}

void EventLoop::handleNewConnection()
{
    // 获取新连接
    int netfd = _acceptor.accept();
    // epoll 添加对于 netfd 的监听
    addEpollReadEvent(netfd);
    // 创建 TcpConnection 的对象
    TcpConnectionPtr conn(new TcpConnection(netfd));
    // 设置三个函数对象
    conn -> setAllCallbacks(
                            _onConnection , 
                            _onMessage , 
                            _onClose
                           );
    // 添加到容器 map
    _conns.insert(std::make_pair(netfd , conn));
    // 调用连接建立时的函数对象
    conn -> handleNewConnectionCallback();
}

void EventLoop::handleMessage(int fd)
{
    // 先通过 fd 查找到 TcpConnection 对象
    auto iter = _conns.find(fd);

    if(iter != _conns.end())
    {
        // 判断连接是否断开
        bool isClosed = iter -> second -> isClosed();

        if(isClosed)
        {
            //连接断开，调用连接断开时的函数对象
            iter->second->handleCloseCallback();
            // 从 epoll 的监听红黑树上删除
            delEpollReadEvent(fd);
            // 从 map 中删除
            _conns.erase(fd);
        }
        else
        {
            // 发送信息过来，要调用消息到达时的函数对象
            iter->second->handleMessageCallback();
        }
    }
}

int EventLoop::createEpollFd()
{
    int fd = epoll_create1(0);

    if(fd < 0)
    {
        perror("epoll_create1");
    }

    return fd;
}


void EventLoop::addEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev, 0 , sizeof(ev));
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(_epfd , EPOLL_CTL_ADD , fd , &ev);

    if(ret < 0)
    {
        perror("epoll_ctl");
    }
}

void EventLoop::delEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev , 0 , sizeof(ev));
    ev.data.fd = fd;
    int ret = epoll_ctl(_epfd , EPOLL_CTL_DEL , fd , &ev);

    if(ret < 0)
    {
        perror("epoll_ctl");
    }
}

} // end of namespace wd
